package damas.modelo;

import java.util.LinkedList;

import damas.gui.DamasGui;
import utils.Pair;

/**
 * Clase que representa el modelo del juego, contiene todo lo referente a estado, varios m�todos de esta clase llaman o utilizan m�todos
 * de la clase {@code DamasEstado}.
 * <p>
 * Esta clase se encarga principalmente de mantener el estado del juego en relaci�n a jugadores e informaci�n extra para el juego
 * (Como ser el fondo del tablero), todos lo que sea estrictamente estado del problema es responsabilidad de {@code DamasEstado}
 *
 * @author Sim�n Emmanuel Guti�rrez Brida
 * @version 0.1
 * @see DamasModelo#mover(utils.Pair, utils.Pair)
 * @see DamasModelo#vacio(utils.Pair)
 * @see DamasModelo#fichaEn(utils.Pair)
 * @see DamasModelo#esDama(utils.Pair)
 * @see DamasModelo#fichasComidas(int)
 *
 */
public abstract class DamasModelo
{
    public static final int NEGRA        = DamasEstado.NEGRA;
    public static final int ROJA         = DamasEstado.ROJA;
    public static final int DAMA         = DamasEstado.DAMA;
    public static final int FONDO_NEGRO  = DamasEstado.FONDO_NEGRO;
    public static final int FONDO_BLANCO = DamasEstado.FONDO_BLANCO;

    private   DamasGui    gui;
    private   DamasEstado estado;
    private   String[]    nombresJugadores;
    private   int[]       coloresJugadores;
    private   boolean[]   cerebrosJugadores;

    /**
     * Constructor de la clase, crea el fondo del tablero y define valores por defecto para los jugadores
     * @param estado : el estado basico del juego : {@code DamasEstado}
     * @param gui : la interfaz gr�fica del juego : {@code DamasGui}
     */
    public DamasModelo(DamasEstado estado, DamasGui gui)
    {
        this.estado = estado;
        if (estado == null)
        	System.out.println("se pudrio todo");
        this.gui = gui;
        this.nombresJugadores  = new String[] {"player1", "player2"};
        this.coloresJugadores  = new int[] {ROJA, NEGRA};
        this.cerebrosJugadores = new boolean[] {false, false};
    }

    /**
     * reestablece el tablero inicial y la cantidad de fichas comidas
     */
    abstract public void reset();


    /**
     * Mueve una ficha
     * @param inicio : la posici�n actual de la ficha a mover : {@code Pair<Integer,Integer>}
     * @param destino : la posici�n a la cual se quiere mover la ficha : {@code Pair<Integer,Integer>}
     * @return true si la movida es parte de una cadena de capturas, si sigue jugando el mismo jugador : {@code boolean}
     */
    abstract public boolean mover(Pair<Integer, Integer> inicio, Pair<Integer, Integer> destino);

    /**
     * @param pos : una posici�n del tablero : {@code Pair<Integer,Integer>}
     * @return si el tablero est� libre en {@code pos} : {@code boolean}
     */
    abstract public boolean vacio(Pair<Integer, Integer> pos);

    /**
     * @param pos : una posici�n del tablero : {@code Pair<Integer,Integer>}
     * @return que ficha hay en {@code pos} : {@code int}
     * <hr>
     * <b>Las respuestas posibles son:
     * <li>ficha negra   : NEGRA</li>
     * <li>ficha roja    : ROJA</li>
     * <li>dama negra    : NEGRA*DAMA</li>
     * <li>dama roja     : ROJA*DAMA</li>
     * <li>ninguna ficha : 0</li></b>
     */
    abstract public int fichaEn(Pair<Integer, Integer> pos);

    abstract public int fichaEn(int fila, int columna);

    /**
     * @param pos : una posici�n del tablero : {@code Pair<Integer,Integer>}
     * @return true si tablero en {@code pos} es una dama : {@code boolean}
     */
    abstract public boolean esDama(Pair<Integer, Integer> pos);

    /**
     * Retorna las fichas comidas por un jugador (segun su color)
     * @param color : el jugador del que se intenta averiguar las fichas comidas : {@code int}
     * @return fichas comidas por el jugador
     * <hr>
     * Este m�todo se llamar�a con
     * <li><pre>fichasComidas(DamasModelo.ROJA)</pre></li>
     * <li><pre>fichasComidas(DamasModelo.NEGRA)</pre></li>
     */
    abstract public int fichasComidas(int color);

    abstract public LinkedList<Pair<Integer, Integer>> puedeComerDesde(int color);

    abstract public Pair<Integer, Integer> posicionPostComida(Pair<Integer, Integer> pos);

    public boolean puedeComer(Pair<Integer, Integer> pos)
    {
        return estado.puedeComer(pos);
    }


    public DamasEstado obtenerEstado()
    {
        return this.estado;
    }

    public void definirEstado(DamasEstado estado)
    {
        this.estado = estado;
    }

    public boolean esMax()
    {
        return this.estado.isMax();
    }

    public LinkedList<Pair<Pair<Integer, Integer>, Pair<Integer, Integer>>> movimientosPosibles(int colorJugador)
    {
        return this.estado.movimientosPosibles(colorJugador);
    }

    public boolean puedeComerYNoLoHace(Pair<Integer, Integer> inicio)
    {
        return estado.puedeComerYNoLoHace(inicio);
    }
    public boolean esMin()
    {
        return this.estado.isMin();
    }

    public boolean ganoMax()
    {
        return this.estado.maxWins();
    }

    public boolean ganoMin()
    {
        return this.estado.minWins();
    }

    public boolean juegoTermino()
    {
        return this.estado.isFinal();
    }

    public int fondoEn(Pair<Integer, Integer> pos)
    {
        return this.estado.fondoEn(pos.getFirstElem(), pos.getSecondElem());
    }

    public int fondoEn(int fil, int col)
    {
        return this.estado.fondoEn(fil, col);
    }

    public boolean esHumano(int color)
    {
        int jugador = (coloresJugadores[0] == color ? 0 : 1);
        return !cerebrosJugadores[jugador];
    }

    public String nombreJugador(int color)
    {
        int jugador = (coloresJugadores[0] == color ? 0 : 1);
        return nombresJugadores[jugador];
    }

    public int colorJugador(int turno)
    {
        return coloresJugadores[turno];
    }

    public void definirNombre(int jugador, String nombre)
    {
        this.nombresJugadores[jugador] = nombre;
    }

    public void definirColor(int jugador, int color)
    {
        this.coloresJugadores[jugador] = color;
    }

    public void definirCerebro(int jugador, boolean cerebro)
    {
        this.cerebrosJugadores[jugador] = cerebro;
    }

    public void startGUI()
    {
        this.gui.habilitarTablero();
        this.gui.getJugador1Label().setText(nombresJugadores[0] + (cerebrosJugadores[0] ? "(AI)" : "(Human)"));
        this.gui.getJugador2Label().setText(nombresJugadores[1] + (cerebrosJugadores[1] ? "(AI)" : "(Human)"));
        this.gui.getColor1Label().setText(coloresJugadores[0] == DamasModelo.ROJA ? "ROJAS" : "NEGRAS");
        this.gui.getColor2Label().setText(coloresJugadores[1] == DamasModelo.ROJA ? "ROJAS" : "NEGRAS");
        if (this.coloresJugadores[0] == DamasModelo.ROJA)
        {
            this.estado.setMax();
        }
        else
        {
            this.estado.setMin();
        }
        update();
    }

    public void update()
    {
        this.gui.update(this);
    }

    public void interaccionTablero(boolean habilitar)
    {
        this.gui.habilitarInteraccionTablero(habilitar);
    }

    public void habilitarPreferencias()
    {
        this.gui.habilitarPreferencias(true);
    }

    public void deshabilitarPreferencias()
    {
        this.gui.habilitarPreferencias(false);
    }

    public void mostrarGUI()
    {
        this.gui.setEnabled(true);
        this.gui.setVisible(true);
    }

    public void deshabilitarTablero()
    {
        this.gui.deshabilitarTablero();
    }

}